#pragma once

#include <angelscript.h>
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <boostext/util/make_shared.hpp>
#include <engine.core/noncopyable.hpp>

#include "exports.hpp"
#include "pointer.hpp"

// Debugging
#include "Debugger.hpp"

// Reflection
#include "Reflectable.hpp"
#include "Function.hpp"
#include "Variable.hpp"




namespace Engine
{
	namespace Script
	{
		template class ENGINE_SCRIPT_API pointer<asIScriptContext>;




		class ENGINE_SCRIPT_API Context
			: public noncopyable
		{
		public:

			SHARED(Context);

			enum State
			{
				Executing,
				Idle
			};

			typedef boost::shared_ptr<Context>   ptr;

		protected:

			Context(pointer<asIScriptEngine> engine, Reflectable::weak_ptr reflectable);
			virtual void post_create(ptr _this);

		public:

			MAKE_SHARED2(Context, pointer<asIScriptEngine>, Reflectable::weak_ptr);



			/**
			 * @returns the state of the context, either executing or idle
			 */
			State state() const;

			/**
			 * Attaches a debugger to the context.
			 */
			void attach(Debugger::ptr debugger);


			void prepare(int funcId);
			void setObject(void* object);
			void setArgByte(asUINT arg, asBYTE value);
			void setArgWord(asUINT arg, asWORD value);
			void setArgDWord(asUINT arg, asDWORD value);
			void setArgQWord(asUINT arg, asQWORD value);
			void setArgFloat(asUINT arg, float value);
			void setArgDouble(asUINT arg, double value);
			void setArgAddress(asUINT arg, void* addr);
			void setArgObject(asUINT arg, void* obj);
			void execute();
			asBYTE getReturnByte();
			asWORD getReturnWord();
			asDWORD getReturnDWord();
			asQWORD getReturnQWord();
			float getReturnFloat();
			double getReturnDouble();
			void* getReturnAddress();
			void* getReturnObject();
			void* getAddressOfReturnValue();



			//
			// Everything related to reflection, stack-/variable inspection, etc..
			//

			/**
			 * @returns the callstack
			 * @throws when the context is not executing
			 */
			Script::Callstack callstack() const;

			/**
			 * @returns all global variables
			 */
			std::vector<Variable> globals() const;

			/**
			 * @returns all variables from the given stack level
			 * @info the stack level refers to the nth function in the vector, returned by callstack()
			 */
			std::vector<Variable> variables(std::size_t stackLevel) const;

		protected:

			void lineCallback(asIScriptContext*);

		private:

			weak_ptr                    m_this;
			pointer<asIScriptContext>   m_context;
			Debugger::ptr               m_debugger;
			Reflectable::weak_ptr       m_reflectable;
			State                       m_state;
		};
		///////////////////////////////////////////////////////////////////////////////////////////
	}
	///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////
